#ifndef GOBANG_H
#define GOBANG_H
#include <vector>
#include <stdexcept>
#include <iostream>
#include <utility>
#include <set>
#include <iomanip>
#include <string>
#include <algorithm>
#include <climits>
enum class GameState;

using std::vector;
using std::invalid_argument;
using std::cout;
using std::endl;
using std::pair;
using std::set;
using std::max;
using std::setw;
using std::string;
using std::to_string;
using std::min;
using std::sort;

class Gobang {
public:
	Gobang();
	void printBoard();
	bool checkWin(int row, int col, char player);
	bool isBoardFull();
	GameState play(int row, int col);
	void undo();
	const vector<vector<char>>& getBoard();
	void get1dBoard(std::vector<unsigned char>& res);
	pair<int, int> bestMove(char player);
	char getCurrentPlayer();
	void printScoreRecord();
	string getScoreRecordTable();
	void setDifficulty(int difficulty);

private:
	bool isValidMove(int row, int col);
	const int SIZE = 15;
	vector<vector<char>> board;
	char currentPlayer; // 'O'为先手，'X'为后手
	vector<pair<int, int>> historyO;
	vector<pair<int, int>> historyX;
	//set<pair<int, int>> neighbors;
	const int directions[4][2] = { {0, 1}, {1, 0}, {1, 1}, {1, -1} };  // 垂直、水平、斜右下、斜左下 
	vector<vector<vector<int>>> scoreRecordTable;
	/*vector< vector<vector<vector<int>>> > scoreRecordTableList;*/
	int isInInfluenceArea(int row1, int col1, int row2, int col2);
	int evaluate_point(int row, int col, int direction);
	static const vector<pair<vector<char>, int>> scoreTable;
	int ScoreO = 0;
	int ScoreX = 0;
	int difficulty = 3;
	const int enermy_ratio = 2;
	int alphaBeta(int alpha, int beta, int depth, bool isMaxmizing, char maxmizingPlayer);
	set<pair<int, int>> getNeighborCells();
	bool hasWin = false;
	int alphaBetaCalls;
	int alphaBetaCutoffs;
	vector<pair<int, pair<int, int>>> sortCells(const set<pair<int, int>>& emptyCells, char player);
	bool matchPattern(const std::vector<char>& vec, const std::vector<char>& pattern);
};

enum class GameState {
	OnGoing,
	O_Win,
	X_Win,
	Draw,
	InvalidMove,
};
#endif